using System;
using System.Collections.Generic;
using System.Reflection;

namespace Common.Dispatcher
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class CodeTypeConverter
    {
        private Type _FromType;
        /// <summary></summary>
        public Type FromType
        {
            get { return _FromType; }
            set { _FromType = value; }
        }

        private Type _ToType;
        /// <summary></summary>
        public Type ToType
        {
            get { return _ToType; }
            set { _ToType = value; }
        }

        private Dictionary<string,string> _FieldMappings;
        /// <summary></summary>
        public Dictionary<string,string> FieldMappings
        {
            get { return _FieldMappings; }
            set { _FieldMappings = value; }
        }

        //private List<CodeFieldMapper> _FieldMappers;
        /// <summary></summary>
        public CodeTypeConverter(Type fromType, Type toType)
        {
            this._FromType = fromType;
            this._ToType = toType;
            //this._FieldMappers = fieldMappers;
            this._FieldMappings=new Dictionary<string, string>();
            this.InferFieldMappings();
        }

        private void InferFieldMappings()
        {
            Dictionary<string, Type> fromMembers = CodeTypeConverter.GetReadableMembers(this._FromType);
            Dictionary<string, Type> toMembers = CodeTypeConverter.GetWritableMembers(this._ToType);
            foreach(string fromFieldName in fromMembers.Keys)
            {
                if(toMembers.ContainsKey(fromFieldName))
                {
                    if(fromMembers[fromFieldName]==toMembers[fromFieldName])
                    {
                        this._FieldMappings.Add(this._FromType.Name+"."+fromFieldName,this._ToType.Name +"."+fromFieldName);
                    }
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Dictionary<string,Type> GetReadableMembers(Type type)
        {
            Dictionary<string, Type> readableMembers = new Dictionary<string, Type>();
            
            FieldInfo[] fromFields = type.GetFields();
            foreach (FieldInfo fromField in fromFields)
            {
                readableMembers.Add(fromField.Name, fromField.FieldType);
            }
            PropertyInfo[] fromProperties = type.GetProperties();
            foreach (PropertyInfo fromProp in fromProperties)
            {
                if (fromProp.CanRead)
                {
                    readableMembers.Add(fromProp.Name, fromProp.PropertyType);
                }
            }
            return readableMembers;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Dictionary<string, Type> GetWritableMembers(Type type)
        {
            Dictionary<string, Type> writableMembers = new Dictionary<string, Type>();
            FieldInfo[] fromFields = type.GetFields();
            foreach (FieldInfo fromField in fromFields)
            {
                writableMembers.Add(fromField.Name, fromField.FieldType);
            }
            PropertyInfo[] fromProperties = type.GetProperties();
            foreach (PropertyInfo fromProp in fromProperties)
            {
                if (fromProp.CanWrite)
                {
                    writableMembers.Add(fromProp.Name, fromProp.PropertyType);
                }
            }
            return writableMembers;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="excludingMembersFromSubType"></param>
        /// <returns></returns>
        public static Dictionary<string,Type> GetWritableMembersFromType(Type type, Type excludingMembersFromSubType)
        {
            Dictionary<string,Type> baseMemberNames = CodeTypeConverter.GetWritableMembers(excludingMembersFromSubType);

            Dictionary<string, Type> writableMembers = CodeTypeConverter.GetWritableMembers(type);
            if(writableMembers !=null && baseMemberNames !=null && writableMembers.Count>0 && baseMemberNames.Count>0)
            {
                string[] memberNames=new string[writableMembers.Count];
                writableMembers.Keys.CopyTo(memberNames, 0);
                for(int i=0;i<memberNames.Length;i++)
                {
                    if(baseMemberNames.ContainsKey(memberNames[i]))
                    {
                        writableMembers.Remove(memberNames[i]);
                    }
                }
            }
            
            return writableMembers;
        }
    }
}
